/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package iteracon.stack.iterator;

import java.util.ListIterator;
import iteracon.stack.Stack;
import iteracon.stack.Stk;

/**
 * will separate stack in two with current position as pivot
 * list iterator for stack
 * @author martin
 */
public class Pulley<T> implements ListIterator<T>{
  private Stk<T> _left,
                 _right;
  /**
   * constructor
   * @param left as stack
   * @param right as stack
   */
  private Pulley(final Stk left, final Stk right){
    _left=left;
    _right=right;
  }
  /**
   * factory from begining
   * @param <T> as type
   * @param stack as current stack to iterate
   * @return new pulley
   */
  public static<T> ListIterator<T> fromStack(final Stk<T> stack){
    Stk<T> _left = stack;
    return new Pulley<T>(_left,Stack.make());
  }
  /**
   * factory from index
   * @param <T> as type
   * @param stack as stack
   * @param index as int
   * @return new pulley
   */
  public static<T> ListIterator<T> fromStackAtIndex(final Stk<T> stack, int index){
    if (index >= stack.size())
      throw new IndexOutOfBoundsException();
    Stk<T> _left = stack,
           _right = Stack.make();
    for (int i=0;i<index;i++){
      _right = _right.push(_left.top());
      _left = _left.pop();
    }
    return new Pulley<T>(_left,_right);
  }
  
  /**
   * factory from already positionned stack
   * @param <T> as type
   * @param stack as complete stack
   * @param up as part of the complete stack
   * @return new pulley
   */
  public static<T> ListIterator<T> fromStackUp(final Stk<T> stack, final Stk<T> up){
    Stk<T> _right = Stack.make();
    for (T t : stack)
      if (!t.equals(up.top()))
        _right = _right.push(t);
      else
        return new Pulley(up,_right);
    throw new IndexOutOfBoundsException("up stack not in");
  }
  
  @Override
  public boolean hasNext() {
    return _left.size()!=0;
  }
  
  @Override
  public T next() {
    _right = _right.push(_left.top());
    _left = _left.pop();
    return _right.top();
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException("Immutable type");
  }

  @Override
  public boolean hasPrevious() {
    return _right.size()!=0;
  }

  @Override
  public T previous() {
    _left = _left.push(_right.top());
    _right = _right.pop();
    return _left.top();
  }

  @Override
  public int nextIndex() {
    return _left.size();
  }

  @Override
  public int previousIndex() {
    return _left.size()-1;
  }

  @Override
  public void set(T e) {
    throw new UnsupportedOperationException("immutable type");
  }

  @Override
  public void add(T e) {
    throw new UnsupportedOperationException("immutable type");
  }
  
}
